/*
 * SdlEventManager.cpp
 *
 *  Created on: 2016年5月17日
 *      Author: terry
 */

#include "SdlEventManager.h"
#include "CLog.h"
#include <string.h>

namespace sdl
{

static EventManagerPtr s_manager;

EventManagerPtr EventManager::create()
{
	if (!s_manager)
	{
		s_manager.reset(new EventManager());
		s_manager->open();
	}
	return s_manager;
}

void EventManager::destroy(EventManagerPtr& manager)
{
	manager.reset();

	if (s_manager && s_manager.use_count() <= 1)
	{
		s_manager->close();
		s_manager.reset();
	}
}


EventManager::EventManager()
{
}

EventManager::~EventManager()
{
	close();
}

int EventManager::open()
{
	if (isOpen())
	{
		return 0;
	}

	start();

	return 0;
}

void EventManager::close()
{
	if (isRunning())
	{
		stop();
	}

	comn::AutoCritSec lock(m_cs);
	m_handlerMap.clear();
}

bool EventManager::isOpen()
{
	return isRunning();
}

bool EventManager::add(Uint32 winID, EventHandler* pHandler)
{
    if (!pHandler)
    {
        return false;
    }

    comn::AutoCritSec lock(m_cs);

    EventHandlerMap::value_type val(winID, pHandler);
    std::pair< EventHandlerMap::iterator, bool > res = m_handlerMap.insert(val);
    return res.second;
}

void EventManager::remove(Uint32 winID)
{
    comn::AutoCritSec lock(m_cs);
    m_handlerMap.erase(winID);
}

int EventManager::run()
{
	while (!m_canExit)
	{
		SDL_Event event;
		if (SDL_WaitEvent(&event))
		{
			if (SDL_QUIT == event.type)
			{
				broadcastEvent(event);
			}
			else
			{
				handleEvent(event);
			}
		}
	}
	return 0;
}

bool EventManager::startup()
{
	return true;
}

void EventManager::cleanup()
{
	//
}

void EventManager::doStop()
{
    SDL_Event event;
    memset(&event, 0, sizeof(event));
    event.type = SDL_QUIT;

    SDL_PushEvent(&event);
}

void EventManager::handleEvent(SDL_Event& event)
{
	bool found = false;
	if (event.type == SDL_WINDOWEVENT)
	{
		found = handleWindowEvent(event.window.windowID, event);
	}
	else if ((event.type == SDL_KEYDOWN) || (event.type == SDL_KEYUP))
	{
		found = handleWindowEvent(event.key.windowID, event);
	}
	else if ((event.type == SDL_TEXTEDITING) || (event.type == SDL_TEXTINPUT))
	{
		found = handleWindowEvent(event.text.windowID, event);
	}
	else if ((event.type >= SDL_MOUSEMOTION) && (event.type <= SDL_MOUSEWHEEL))
	{
		found = handleWindowEvent(event.motion.windowID, event);
	}
	else if ((event.type >= SDL_USEREVENT) && (event.type <= SDL_LASTEVENT))
	{
		if (EVENT_MANAGER == event.type)
		{
			handleManagerEvent(event);
			found = true;
		}
		else
		{
			found = handleWindowEvent(event.user.windowID, event);
		}
	}

	if (!found)
	{
		broadcastEvent(event);
	}
}

void EventManager::broadcastEvent(SDL_Event& event)
{
    comn::AutoCritSec lock(m_cs);

    EventHandlerMap::iterator it = m_handlerMap.begin();
    for (; it != m_handlerMap.end(); ++ it)
    {
        (it->second)->handleEvent(event);
    }
}

bool EventManager::handleWindowEvent(Uint32 winID, SDL_Event& event)
{
    bool found = false;

    comn::AutoCritSec lock(m_cs);
    EventHandlerMap::iterator it = m_handlerMap.find(winID);
    if (it != m_handlerMap.end())
    {
        (it->second)->handleEvent(event);
        found = true;
    }
    return found;
}

void EventManager::handleManagerEvent(SDL_Event& sdlEvent)
{
	//
}



} /* namespace sdl */
